import { _decorator, CCFloat, Collider, Component, ICollisionEvent, PhysicsSystem, RigidBody, SkeletalAnimation, v3, Vec3, Node, Animation, SkeletalAnimationState} from 'cc';
const { ccclass, property } = _decorator;
import { StateDefine } from "./StateDefine"
import { MathUtil } from '../utils/MathUtil';
import { ActorProperty } from "./ActorProperty"
import { Projectile } from './Projectile';
import { Events } from '../events/Events';

let tempVelocity = v3();

@ccclass('Actor')
export class Actor extends Component {

    currState:StateDefine = StateDefine.Idle;

    @property(SkeletalAnimation)
    skeletalAnimation:SkeletalAnimation = null;

    rigidBody:RigidBody = null;
    collider:Collider = null;

    @property(CCFloat)
    linearSpeed: number = 1.0;

    @property(CCFloat)
    angularSpeed: number = 10;

    input:Vec3 = v3();

    actorProperty: ActorProperty = new ActorProperty();

    start() {
        this.rigidBody = this.node.getComponent(RigidBody);
        this.collider = this.node.getComponent(Collider);
        this.skeletalAnimation?.on(Animation.EventType.FINISHED, this.onAnimationFinished, this);        
        this.collider.on("onTriggerEnter", this.onTriggerEnter, this);
    }

    update(deltaTime: number) {

        this.doRotation();

        switch(this.currState)
        {

            case StateDefine.Run:
                // move 
                this.doMove();
                break;
            case StateDefine.Die:
                break;
        }
    }

    doRotation()
    {
        tempVelocity.x = 0;
        tempVelocity.z = 0;

        const angle = MathUtil.signAngle(this.node.forward, this.input, Vec3.UP);
        tempVelocity.y = angle * this.angularSpeed;
        this.rigidBody.setAngularVelocity(tempVelocity);
    }
    

    doMove()
    {
        // 速度 = 方向（node.forward) * 基础速度 * 因子（遥感输入【加速 减速（暂不实现）】）
        const speed = this.input.length() * this.linearSpeed;
        tempVelocity.x = this.node.forward.x * speed;
        tempVelocity.y = 0;
        tempVelocity.z = this.node.forward.z * speed;
        this.rigidBody.setLinearVelocity(tempVelocity);

    }

    stopMove()
    {
        this.rigidBody.setLinearVelocity(Vec3.ZERO);
    }

    /**
     * 改变玩家状态
     */
    changeState(destState:StateDefine){

        if (destState == this.currState && destState != StateDefine.Hit) {
            return;
        }

        if(this.currState == StateDefine.Die)
            return;

        if(destState != StateDefine.Run)
        {
            this.stopMove();
        }
       
        this.currState = destState;
        this.skeletalAnimation.crossFade(this.currState, 0.2);
    }

    /**
     * 复活
     */
    respawn(){
        this.currState = StateDefine.Idle;
        this.skeletalAnimation.crossFade(this.currState, 0.3);
    }



    /**
     * 碰撞检测
     */
    onTriggerEnter(event: ICollisionEvent)
    {
        // 与默认组碰撞不处理
        if(event.otherCollider.getGroup() == PhysicsSystem.PhysicsGroup.DEFAULT){
            return;
        }

        const projectile = event.otherCollider.getComponent(Projectile);
        
        const hostActor = projectile.host.getComponent(Actor);
        
        let hurtDirtion = v3();
        Vec3.subtract(hurtDirtion, this.node.worldPosition, projectile.node.worldPosition);
        hurtDirtion.normalize();
        this.hurt(hostActor.actorProperty.attack, hurtDirtion, hostActor);
    }

    onAnimationFinished(eventType: Animation.EventType, state: SkeletalAnimationState) {
        if (state.name == StateDefine.Attack) {
            this.changeState(StateDefine.Idle);
        }

        if (state.name == StateDefine.Hit) {
            this.changeState(StateDefine.Idle);
        }
    }


    /**
     * 受到攻击
     * @param damage 伤害值
     * @param hurtDirtion 攻击方向
     */
    hurt(damage:number, hurtDirtion:Vec3, hurtSrc:Actor | null){

        if(this.currState == StateDefine.Die)
            return;

        this.actorProperty.hp -= damage;
        this.node.emit(Events.OnHurt, this.actorProperty.hp / this.actorProperty.maxHp);
        if(this.actorProperty.hp <= 0)
        {
            // 通知攻击方,你已经杀死了一个角色
            hurtSrc?.node.emit(Events.OnKill, this.node);
            this.onDie();
        }else{
            this.changeState(StateDefine.Hit);
        }

        // 增大力
        hurtDirtion.multiplyScalar(2);
        this.rigidBody?.applyImpulse(hurtDirtion);
    }


    onDie() {
        if (this.currState == StateDefine.Die) {
            return;
        }
        this.changeState(StateDefine.Die);
        this.node.emit(Events.OnDie, this.node)
    }
}

